package cc.rengu.oltp.utility.util;


import org.apache.commons.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HmacUtil {
    private static final String ALGORITHM_TYPE_SHA512 = "SHA-512";
    private static final String ALGORITHM_HMAC_SHA1 = "HmacSHA1";
    private static final String ALGORITHM_HMAC_SHA256 = "HmacSHA256";
    private static final String ALGORITHM_HMAC_SHA512 = "HmacSHA512";

    /**
     * 生成HMAC_SHA1加签串
     *
     * @param blockString 加签数据
     * @param signKey     密钥
     * @return 加签字符串
     */
    public static String generateHmacSHA1SignString(String blockString, String signKey) {
        try {
            SecretKey secretKey = new SecretKeySpec(signKey.getBytes(StandardCharsets.UTF_8), ALGORITHM_HMAC_SHA1);
            Mac mac = Mac.getInstance(ALGORITHM_HMAC_SHA1);
            mac.init(secretKey);
            return StringUtil.binaryToHexString(mac.doFinal(blockString.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 生成HMAC_SHA256加签串
     *
     * @param blockString 加签数据
     * @param signKey     密钥
     * @return 加签字符串
     */
    public static String generateHmacSHA256SignString(String blockString, String signKey) {
        try {
            SecretKey secretKey = new SecretKeySpec(signKey.getBytes(StandardCharsets.UTF_8), ALGORITHM_HMAC_SHA256);
            Mac mac = Mac.getInstance(ALGORITHM_HMAC_SHA256);
            mac.init(secretKey);
            return StringUtil.binaryToHexString(mac.doFinal(blockString.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 校验HMAC_SHA256加签串
     *
     * @param verifyData  校验加签域
     * @param blockString 原始加签数据
     * @param signKey     密钥
     * @return true-成功，false-失败
     */
    public static boolean verifyHmacSHA256SignString(String verifyData, String blockString, String signKey) {
        String signData = generateHmacSHA256SignString(blockString, signKey);
        if (null == signData) {
            return false;
        } else {
            return verifyData.equalsIgnoreCase(signData);
        }
    }

    /**
     * 生成HMAC_SHA256加签串
     *
     * @param blockString 加签数据
     * @param signKey     密钥
     * @return 加签字符串
     */
    public static byte[] generateHmacSHA256Sign(String blockString, String signKey) {
        try {
            SecretKey secretKey = new SecretKeySpec(signKey.getBytes(StandardCharsets.UTF_8), ALGORITHM_HMAC_SHA256);
            Mac mac = Mac.getInstance(ALGORITHM_HMAC_SHA256);
            mac.init(secretKey);
            return mac.doFinal(blockString.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 生成HMAC_SHA512加签串
     *
     * @param blockString 加签数据
     * @param signKey     密钥
     * @return 加签字符串
     */
    public static String generateHmacSHA512SignString(String blockString, String signKey) {
        try {
            SecretKey secretKey = new SecretKeySpec(signKey.getBytes(StandardCharsets.UTF_8), ALGORITHM_HMAC_SHA512);
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            return StringUtil.binaryToHexString(mac.doFinal(blockString.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 校验HMAC_SHA512加签串
     *
     * @param verifyData  校验加签域
     * @param blockString 原始加签数据
     * @param signKey     密钥
     * @return true-成功，false-失败
     */
    public static boolean verifyHmacSHA512SignString(String verifyData, String blockString, String signKey) {
        String signData = generateHmacSHA512SignString(blockString, signKey);
        if (null == signData) {
            return false;
        } else {
            return verifyData.equalsIgnoreCase(signData);
        }
    }

    /**
     * SHA512加密
     *
     * @param srcString 需要加密的字符串
     * @return 加密后的字符串
     */
    public static String encryptStringByHmacSHA512(String srcString) {
        if (srcString != null && srcString.length() > 0) {
            try {
                MessageDigest messageDigest = MessageDigest.getInstance(ALGORITHM_TYPE_SHA512);
                messageDigest.update(srcString.getBytes(StandardCharsets.UTF_8));
                return StringUtil.binaryToHexString(messageDigest.digest());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * Base64加密
     *
     * @param srcString 需要加密的字符串
     * @return 加密后的字符串
     */
    public static String encryptStringByBase64(String srcString) {
        try {
            return Base64.encodeBase64String(srcString.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * base64编码的变体，由于base64中的=、／和+不适合Url传递，
     * 因此需要将这三个符号替换掉，规则是去掉=，+替换为-，／替换为_
     *
     * @param srcString 源字符串
     * @return 转换后的字符串
     */
    public static String base64Url(String srcString) {
        try {
            String base64Str = Base64.encodeBase64String(srcString.getBytes());
            base64Str = base64Str.replace("=", "");
            base64Str = base64Str.replace("+", "-");
            base64Str = base64Str.replace("/", "_");
            return base64Str;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}